/** * Copyright (C) 2016 Patrice Brend'amour <patrice@brendamour.net> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.brendamour.jpasskit.server; import java.util.Properties; import org.apache.commons.lang3.StringUtils; import org.restlet.Component; import org.restlet.Server; import org.restlet.data.Parameter; import org.restlet.data.Protocol; import org.restlet.routing.Router; import org.restlet.util.Series; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PKRestServer { private static final Logger LOGGER = LoggerFactory.getLogger(PKRestServer.class); private static final String SERVER_BIND_IP_KEY = "rest.bindIP"; private static final String SERVER_BIND_PORT_KEY = "rest.bindPort"; private static final String SERVER_BIND_SSL_ENABLED_KEY = "rest.ssl.enabled"; private static final String SERVER_BIND_SSL_KEYSTORE_PATH_KEY = "rest.ssl.keystore.path"; private static final String SERVER_BIND_SSL_KEYSTORE_TYPE_KEY = "rest.ssl.keystore.type"; private static final String SERVER_BIND_SSL_KEYSTORE_PASSWORD_KEY = "rest.ssl.keystore.password"; private static final String SERVER_BIND_SSL_KEY_PASSWORD_KEY = "rest.ssl.key.password"; private Properties serverConfigurationProperties; private Component restTrustedServerComponent; private Server restTrustedServer; private final IPKRestletServerResourceFactory pkRestletServerResourceFactory; private String version = "v1"; public PKRestServer(final Properties serverConfigurationProperties, final IPKRestletServerResourceFactory pkRestletServerResourceFactory) { this.serverConfigurationProperties = serverConfigurationProperties; this.pkRestletServerResourceFactory = pkRestletServerResourceFactory; } public final void start() throws Exception { LOGGER.info("####################### Starting PassKitServer ###########################"); checkConfigurationProperties(); createPKRestWebService(); restTrustedServerComponent.start(); } private void checkConfigurationProperties() { if (serverConfigurationProperties != null) { boolean allPropertiesSet = serverConfigurationProperties.containsKey(SERVER_BIND_IP_KEY) && serverConfigurationProperties.containsKey(SERVER_BIND_PORT_KEY) && serverConfigurationProperties.containsKey(SERVER_BIND_SSL_ENABLED_KEY); if (allPropertiesSet) { LOGGER.debug("Checked properties. Everything we need is present"); return; } } throw new RuntimeException("Server needs to be configured accordingly."); } private void createPKRestWebService() { restTrustedServerComponent = new Component(); String bindIp = serverConfigurationProperties.getProperty(SERVER_BIND_IP_KEY); int bindPort = Integer.parseInt(serverConfigurationProperties.getProperty(SERVER_BIND_PORT_KEY)); boolean useSSL = Boolean.parseBoolean(serverConfigurationProperties.getProperty(SERVER_BIND_SSL_ENABLED_KEY)); Protocol httpProtocol = Protocol.HTTP; if (useSSL) { httpProtocol = Protocol.HTTPS; } restTrustedServer = new Server(httpProtocol, bindIp, bindPort); restTrustedServerComponent.getServers().add(restTrustedServer); if (useSSL) { setupSSL(); } final Router router = new Router(restTrustedServerComponent.getContext().createChildContext()); restTrustedServerComponent.getDefaultHost().attach("", router); PKDeviceResourceFactory pkDeviceResourceFactory = new PKDeviceResourceFactory(pkRestletServerResourceFactory); PKPassResourceFactory pkPassResourceFactory = new PKPassResourceFactory(pkRestletServerResourceFactory); PKPersonalizePassResourceFactory pkPersonalizePassResourceFactory = new PKPersonalizePassResourceFactory(pkRestletServerResourceFactory); PKLogResourceFactory pkLogResourceFactory = new PKLogResourceFactory(pkRestletServerResourceFactory); router.attach("/" + version + "/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{serialNumber}", pkDeviceResourceFactory); router.attach("/" + version + "/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}", pkDeviceResourceFactory); router.attach("/" + version + "/passes/{passTypeIdentifier}/{serialNumber}", pkPassResourceFactory); router.attach("/" + version + "/passes/{passTypeIdentifier}/{serialNumber}/personalize", pkPersonalizePassResourceFactory); router.attach("/" + version + "/log", pkLogResourceFactory); LOGGER.debug("Created Restlet components"); } private void setupSSL() { LOGGER.info("Enabling SSL"); String keystorePath = serverConfigurationProperties.getProperty(SERVER_BIND_SSL_KEYSTORE_PATH_KEY); String keystoreType = serverConfigurationProperties.getProperty(SERVER_BIND_SSL_KEYSTORE_TYPE_KEY); String keystorePassword = serverConfigurationProperties.getProperty(SERVER_BIND_SSL_KEYSTORE_PASSWORD_KEY); String keyPassword = serverConfigurationProperties.getProperty(SERVER_BIND_SSL_KEY_PASSWORD_KEY); if (StringUtils.isEmpty(keystorePath) || StringUtils.isEmpty(keystoreType)) { throw new RuntimeException("SSL is enabled but not set up correct. We need at least a keystore path and -type"); } Series<Parameter> parameters = restTrustedServer.getContext().getParameters(); parameters.add("sslContextFactory", "org.restlet.ext.ssl.PkixSslContextFactory"); parameters.add("keystorePath", keystorePath); parameters.add("keystorePassword", keystorePassword); parameters.add("keyPassword", keyPassword); parameters.add("keystoreType", keystoreType); } public final void stop() throws Exception { LOGGER.info("####################### Stopping PassKitServer ###########################"); restTrustedServerComponent.stop(); } }